17 October review

New Data review : “C:\20251016scholars.Rda”

Data Prep Work

Clear data

Load Functions

library(readxl)
library(selenider)
library(rvest)
library(tidyverse)
library(netstat)
library(pingr)
library(jsonlite)
library(stringr)
library(openalexR)
library(readxl)

packages <- c("tidyverse", "scholar", "openalexR", "rvest", "jsonlite")
packages <- c("devtools", "igraph")

fpackage.check <- function(packages) {
    lapply(packages, FUN = function(x) {
        if (!require(x, character.only = TRUE)) {
            install.packages(x, dependencies = TRUE)
            library(x, character.only = TRUE)
        }
    })
}

fsave <- function(x, file = NULL, location = "./data/processed/") {
    ifelse(!dir.exists("data"), dir.create("data"), FALSE)
    ifelse(!dir.exists("data/processed"), dir.create("data/processed"), FALSE)
    if (is.null(file))
        file = deparse(substitute(x))
    datename <- substr(gsub("[:-]", "", Sys.time()), 1, 8)
    totalname <- paste(location, file, "_", datename, ".rda", sep = "")
    save(x, file = totalname)  #need to fix if file is reloaded as input name, not as x. 
}

fload <- function(filename) {
    load(filename)
    get(ls()[ls() != "filename"])
}

fshowdf <- function(x, ...) {
    knitr::kable(x, digits = 2, "html", ...) %>%
        kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
        kableExtra::scroll_box(width = "100%", height = "300px")
}

Access large data file of professors, set of egos for research

Load Dataset - new dataset from Jos

scholars <- fload("C:/Github/labjournal/20251016scholars.Rda") 

New fcolnet function

Define Network Data Helper Function

fcolnet = function(data = scholars, university = c("RU", 'UU'), discipline = "Sociologie", waves = list(c(2015,
    2018), c(2019, 2023), c(2024, 2025)), type = c("first")) {

    university = paste0('(', paste0(university, collapse='|' ), ')')
    discipline = paste0('(', paste0(discipline, collapse='|' ), ')')

    # step 1
    demographics = data$demographics
    sample = which(
        (str_detect(demographics$universiteit.22, university)
            | str_detect(demographics$universiteit.24, university)
            | str_detect(demographics$universiteit.25, university)
        ) & (
            str_detect(demographics$discipline.22, discipline)
            | str_detect(demographics$discipline.24, discipline)
            | str_detect(demographics$discipline.25, discipline)
        ) |> replace_na(FALSE))

    demographics_soc = demographics[sample, ] |> drop_na(id)

    # step 2
    ids = demographics_soc$id |> unique()

    scholars_sel = list() 
    for (id_ in ids){
        scholars_sel[[id_]] = bind_rows(scholars$works) |>
            filter(author_id == id_)
    }
    scholars_sel = bind_rows(scholars$works) 
    

    nwaves = length(waves)
    nets = array(0, dim = c(nwaves, length(ids), length(ids)), dimnames = list(wave = 1:nwaves, ids,
        ids))
    dimnames(nets)

    # step 3
    df_works = tibble(
            works_id = scholars_sel$id, 
            works_author = scholars_sel$authorships, 
            works_year = scholars_sel$publication_year
        )

    df_works = df_works[!duplicated(df_works), ]

    # step 4
    if (type == "first") {
        for (j in 1:length(waves)) {
            df_works_w = df_works[df_works$works_year >= waves[[j]][1] & df_works$works_year <= waves[[j]][2],
                ]
            for (i in 1:nrow(df_works_w)) {
                ego = df_works_w$works_author[i][[1]]$id[1]
                alters = df_works_w$works_author[i][[1]]$id[-1]
                if (sum(ids %in% ego) > 0 & sum(ids %in% alters) > 0) {
                  nets[j, which(ids %in% ego), which(ids %in% alters)] = 1
                }
            }
        }
    }

    if (type == "last") {
        for (j in 1:length(waves)) {
            df_works_w = df_works[df_works$works_year >= waves[[j]][1] & df_works$works_year <= waves[[j]][2],
                ]
            for (i in 1:nrow(df_works_w)) {
                ego = rev(df_works_w$works_author[i][[1]]$id[1])
                alters = rev(df_works_w$works_author[i][[1]]$id[-1])
                if (sum(ids %in% ego) > 0 & sum(ids %in% alters) > 0) {
                  nets[j, which(ids %in% ego), which(ids %in% alters)] = 1
                }
            }
        }
    }
    if (type == "all") {
        for (j in 1:length(waves)) {
            df_works_w = df_works[df_works$works_year >= waves[[j]][1] & df_works$works_year <= waves[[j]][2],
                ]
            for (i in 1:nrow(df_works_w)) {
                egos = df_works_w$works_author[i][[1]]$id
                if (sum(ids %in% egos) > 0) {
                  nets[j, which(ids %in% egos), which(ids %in% egos)] = 1
                }
            }
            diag(nets[j,,]) = 0
        }
    }

    output = list()
    output$data = demographics_soc
    output$nets = nets
    return(output)
}

load Rsiena packages

packages = c(
    "RSiena", "tidyverse",
    'dplyr', 'stringr' # these packages were added to make the code run
)
fpackage.check(packages)
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

Getting Data

Application

Load Data

# from Jos code - Radboud and Utrecht
test1 = fcolnet(scholars, university = c('RU', 'UU')) 
df_ego1 = bind_rows(test1$data)

# Radboud only (where I want to start)
test = fcolnet(scholars, university = c("RU")) #only Radboud 
df_ego = bind_rows(test$data)

Wrangle Data

wave1 = test$nets[1,,]
wave2 = test$nets[2,,]
wave3 = test$nets[3,,]

nets = array(
    data = c(wave1, wave2, wave3),
    dim = c(dim(wave2), 2)
)

net = sienaDependent(nets)

Isolate Gender variable (binary)

# Example from recoding function
#df_ego = df_ego |>
#    mutate(
#        funcs = case_when(
#            functie.22 == "Full Professor" ~ 1,
#            functie.24 == "Full Professor" ~ 1,
#            functie.25 == "Full Professor" ~ 1,
#            .default = 0
#        )
#    )

# Recoding for gender
df_ego = df_ego |>
    mutate(
        female = case_when(
            gender == "female" ~ 1,
            .default = 0
        )
    )
female = coCovar(df_ego$female)

Visualizing RU Waves

# make adjacency matrix with first wave of data
test_wave1ru <- igraph::graph_from_adjacency_matrix(
  test$nets[1,,], #for this example I take the first wave of data. (thus I select the array of networks and take the first matrix)
  mode = c("directed"),
  weighted = NULL,
  diag = FALSE,
  add.colnames = NULL,
  add.rownames = NULL
)

#plot to see if it worked 
plot(test_wave1ru,
  vertex.color = ifelse(df_ego$female == 1, "red", "blue"),
  vertex.label = NA,
  edge.width = 0.2,
  edge.arrow.size =0.2)


dim(test_wave1ru) #check it works 
NULL
sum(is.na(test_wave1ru)) #check it is complete -- if 0 missing values
[1] 0

Visualizing just radboud (both depts) wave 2

test_wave2ru <- igraph::graph_from_adjacency_matrix(
  test$nets[2,,], #for this example I take the first wave of data. (thus I select the array of networks and take the first matrix)
  mode = c("directed"),
  weighted = NULL,
  diag = FALSE,
  add.colnames = NULL,
  add.rownames = NULL
)

#plot to see if it worked 
plot(test_wave2ru,
  vertex.color = ifelse(df_ego$female == 1, "red", "blue"),
  vertex.label = NA,
  edge.width = 0.2,
  edge.arrow.size =0.2)

test_wave3ru <- igraph::graph_from_adjacency_matrix(
  test$nets[3,,], #for this example I take the first wave of data. (thus I select the array of networks and take the first matrix)
  mode = c("directed"),
  weighted = NULL,
  diag = FALSE,
  add.colnames = NULL,
  add.rownames = NULL
)

#plot to see if it worked 
plot(test_wave3ru,
  vertex.color = ifelse(df_ego$female == 1, "red", "blue"),
  vertex.label = NA,
  edge.width = 0.2,
  edge.arrow.size =0.2)

Add in collaborators + their gender?

Descriptive Statistics

NOW - LOOK AT DESCRIPTIVE STATISTICS FOR RU ONLY

igraph::transitivity(test_wave3ru, type = c("localundirected"), isolates = c("NaN", "zero"))
https://openalex.org/A5025020830 https://openalex.org/A5107108074 https://openalex.org/A5062356007 https://openalex.org/A5011326378 
                             NaN                              NaN                              NaN                              NaN 
https://openalex.org/A5055990297 https://openalex.org/A5040086999 https://openalex.org/A5010764981 https://openalex.org/A5042713882 
                      0.04761905                              NaN                       0.00000000                              NaN 
https://openalex.org/A5093927073 https://openalex.org/A5047911137 https://openalex.org/A5072634827 https://openalex.org/A5116748350 
                      1.00000000                              NaN                              NaN                       0.00000000 
https://openalex.org/A5046746723 https://openalex.org/A5085082439 https://openalex.org/A5004797389 https://openalex.org/A5059244275 
                      0.66666667                              NaN                              NaN                              NaN 
https://openalex.org/A5063338887 https://openalex.org/A5107698575 https://openalex.org/A5038364313 https://openalex.org/A5071959536 
                             NaN                              NaN                       0.00000000                              NaN 
https://openalex.org/A5083298960 https://openalex.org/A5025639524 https://openalex.org/A5030685996 https://openalex.org/A5037616102 
                             NaN                              NaN                       0.00000000                              NaN 
https://openalex.org/A5002770121 https://openalex.org/A5060194739 https://openalex.org/A5056184618 https://openalex.org/A5104227161 
                             NaN                              NaN                       0.00000000                              NaN 
https://openalex.org/A5048074496 https://openalex.org/A5062173114 https://openalex.org/A5058254351 https://openalex.org/A5099033606 
                      0.00000000                              NaN                       0.00000000                              NaN 
https://openalex.org/A5056774186 https://openalex.org/A5084918963 https://openalex.org/A5047687982 https://openalex.org/A5066699568 
                             NaN                              NaN                              NaN                       0.00000000 
https://openalex.org/A5043015269 https://openalex.org/A5029360150 https://openalex.org/A5045280782 https://openalex.org/A5030658869 
                      0.00000000                              NaN                              NaN                              NaN 
https://openalex.org/A5056557463 https://openalex.org/A5024195666 https://openalex.org/A5103523883 https://openalex.org/A5093330363 
                             NaN                              NaN                              NaN                              NaN 
https://openalex.org/A5085123027 https://openalex.org/A5035350135 https://openalex.org/A5086908160 https://openalex.org/A5026623706 
                             NaN                       0.16666667                       0.00000000                       0.00000000 
https://openalex.org/A5102070907 https://openalex.org/A5068642001 https://openalex.org/A5075816665 https://openalex.org/A5104078567 
                             NaN                              NaN                              NaN                              NaN 
https://openalex.org/A5064646891 https://openalex.org/A5075710125 https://openalex.org/A5048218319 https://openalex.org/A5037423746 
                             NaN                              NaN                              NaN                              NaN 
https://openalex.org/A5040385638 https://openalex.org/A5080235042 https://openalex.org/A5038009917 https://openalex.org/A5081499440 
                             NaN                              NaN                              NaN                              NaN 
https://openalex.org/A5050680074 https://openalex.org/A5058115048 https://openalex.org/A5100375099 https://openalex.org/A5087380803 
                             NaN                              NaN                              NaN                       0.30000000 
https://openalex.org/A5065325810 https://openalex.org/A5041095675 https://openalex.org/A5017382943 https://openalex.org/A5050786452 
                      1.00000000                              NaN                              NaN                              NaN 
https://openalex.org/A5023395007 https://openalex.org/A5055096981 https://openalex.org/A5016089551 https://openalex.org/A5091348904 
                             NaN                       0.00000000                              NaN                              NaN 
https://openalex.org/A5031002485 https://openalex.org/A5042331969 https://openalex.org/A5066092617 https://openalex.org/A5017636151 
                      0.00000000                              NaN                              NaN                              NaN 
https://openalex.org/A5017637321 https://openalex.org/A5082749336 https://openalex.org/A5018242597 https://openalex.org/A5080593921 
                             NaN                              NaN                              NaN                              NaN 
https://openalex.org/A5053506252 https://openalex.org/A5074062335 https://openalex.org/A5038843493 https://openalex.org/A5019799886 
                             NaN                              NaN                       0.33333333                              NaN 
https://openalex.org/A5023362052 https://openalex.org/A5085493990 https://openalex.org/A5048125830 https://openalex.org/A5003892082 
                             NaN                              NaN                              NaN                       0.00000000 
https://openalex.org/A5002388922 https://openalex.org/A5064349318 https://openalex.org/A5018212005 https://openalex.org/A5112383954 
                             NaN                              NaN                       0.00000000                              NaN 
https://openalex.org/A5038425122 https://openalex.org/A5019957971 https://openalex.org/A5040600354 https://openalex.org/A5037069958 
                             NaN                              NaN                       0.00000000                       1.00000000 
https://openalex.org/A5060015711 https://openalex.org/A5020765315 https://openalex.org/A5095856216 https://openalex.org/A5082048045 
                      0.33333333                              NaN                              NaN                              NaN 
https://openalex.org/A5007673492 https://openalex.org/A5043004626 https://openalex.org/A5025668614 https://openalex.org/A5048988743 
                             NaN                              NaN                              NaN                       0.00000000 
https://openalex.org/A5078173090 https://openalex.org/A5009655338 https://openalex.org/A5004733423 https://openalex.org/A5016107698 
                             NaN                       1.00000000                              NaN                       0.00000000 
https://openalex.org/A5035502020 https://openalex.org/A5050683616 https://openalex.org/A5006416152 https://openalex.org/A5112742337 
                      0.10000000                              NaN                              NaN                              NaN 
https://openalex.org/A5012137641 https://openalex.org/A5030092568 https://openalex.org/A5012273953 https://openalex.org/A5023494442 
                             NaN                              NaN                       0.00000000                              NaN 
https://openalex.org/A5031371982 https://openalex.org/A5068000059 https://openalex.org/A5032041950 https://openalex.org/A5017129862 
                      0.00000000                              NaN                       0.00000000                              NaN 
https://openalex.org/A5030977100 https://openalex.org/A5063497971 https://openalex.org/A5102793963 https://openalex.org/A5018479981 
                             NaN                       0.00000000                              NaN                              NaN 
https://openalex.org/A5079372810 https://openalex.org/A5020071821 https://openalex.org/A5017879057 https://openalex.org/A5013258554 
                             NaN                              NaN                              NaN                       0.00000000 
https://openalex.org/A5002265802 https://openalex.org/A5006081433 https://openalex.org/A5021227718 https://openalex.org/A5065130106 
                             NaN                              NaN                              NaN                       0.00000000 
https://openalex.org/A5062608377 https://openalex.org/A5068892781 https://openalex.org/A5045288860 https://openalex.org/A5085013298 
                      0.00000000                              NaN                              NaN                       0.33333333 
https://openalex.org/A5061402160 https://openalex.org/A5078518573 https://openalex.org/A5046585291 https://openalex.org/A5019204497 
                             NaN                              NaN                              NaN                       0.00000000 
https://openalex.org/A5087435392 https://openalex.org/A5042405723 https://openalex.org/A5001803910 https://openalex.org/A5044445824 
                             NaN                              NaN                       0.33333333                              NaN 
https://openalex.org/A5081620696 https://openalex.org/A5066781342 https://openalex.org/A5057934803 https://openalex.org/A5033572980 
                      0.00000000                              NaN                              NaN                              NaN 
https://openalex.org/A5084821293 https://openalex.org/A5039921154 https://openalex.org/A5008459416 https://openalex.org/A5022243966 
                      0.00000000                              NaN                              NaN                       0.33333333 
https://openalex.org/A5065278343 https://openalex.org/A5074532622 https://openalex.org/A5113457866 https://openalex.org/A5059043231 
                             NaN                              NaN                              NaN                              NaN 
https://openalex.org/A5013379944 https://openalex.org/A5000347656 https://openalex.org/A5026156805 https://openalex.org/A5064944446 
                      0.00000000                       0.00000000                              NaN                              NaN 

Next, moving from local to global transitivity

  • Look at triads for more global transitivity.
  • Note: Global = number of observed over possible - can identify all transitive triads and all possible triads
  • Reviewing dyads - then triads. Since it is undirected, it is less difficult to calculate.
  • Now, looking at triad census vs triad allegation
igraph::triad.census(test_wave3ru) #with plot -- works
 [1] 658675  10658    462     28     68     13      8      2      5      0      0      0      0      0      1      0
sna::triad.census(test$nets[2,,])
        003   012  102 021D 021U 021C 111D 111U 030T 030C 201 120D 120U 120C 210 300
[1,] 650587 16986 1963   37  189   58   56   10   14    0   1    8    4    4   2   1
unloadNamespace("sna")  #I will detach this package again

triad_w2ru <- data.frame(sna::triad.census(test$nets[2,,])) #save as df


igraph::transitivity(test_wave2ru, type = "global")
[1] 0.22
  # Returns: [1] 0.22
sna::gtrans(test$nets[2,,]) #triad census a different way 
[1] 0.2842105
  # Returns: [1] 0.2842105

transitivity_w2 <- (3 * triad_w2ru$X300)/(triad_w2ru$X201 + 3 * triad_w2ru$X300) #X300 is variable for transitive triad (the fully closed triad)
# we multiply by 3 because there are 3 possible transitive triads
transitivity_w2
[1] 0.75
  # Returns: [1] 0.75



# Wave 3
sna::triad.census(test$nets[3,,])
        003   012 102 021D 021U 021C 111D 111U 030T 030C 201 120D 120U 120C 210 300
[1,] 658675 10658 462   28   68   13    8    2    5    0   0    0    0    0   1   0
   # Returns: 003    012   102   021D  021U  021C  111D  111U  030T  030C 201  120D  120U 120C  210  300
   #    [1,]  658675 10658 462   28    68    13     8     2     5    0    0    0     0     0     1   0

unloadNamespace("sna")  #I will detach this package again

triad_w3ru <- data.frame(sna::triad.census(test$nets[3,,])) #save as df


igraph::transitivity(test_wave3ru, type = "global")
[1] 0.1313869
  # Returns: [1] 0.1313869
sna::gtrans(test$nets[3,,]) #triad census a different way 
[1] 0.25
  # Returns: [1] 0.25

transitivity_w3 <- (3 * triad_w3ru$X300)/(triad_w3ru$X201 + 3 * triad_w3ru$X300) #X300 is variable for transitive triad (the fully closed triad)
# we multiply by 3 because there are 3 possible transitive triads
transitivity_w3
[1] NaN
  # Returns: [1] NaN

NEED TO INCLUDE TRIADS - TRANSITIVITY OUTDEGREE AND RECIPROCITY ARE ALWAYS IN THERE, ALSO NEED OUTDEGREE ACTIVITY OR IN DEGREE POPULARITY. ALSO NEED SOMETHING FOR TRANSITIVITY - GWESP VARIABLE AND EFFECTS TO INCLUDE - MAKE SURE TO INCLUDE ONE OF THESE TOO.

Network visualisation: Let’s make size proportional to betweenness score

Rsiena work

Get packages: Jochem’s twostep

fpackage.check(packages)
[[1]]
NULL

Step 1: Define data

Independent variable: gender?

We already know: net <- sienaDependent(nets) (dependent variable) Dependent variable: ties = [net]

mydata <- sienaDataCreate(net, gender) #buggy - why doesnt this work?? 
Error in sienaDataCreate(net, gender) : 
  constant covariate incorrect node set: gender

Step 2. Look at effects

effectsDocumentation(myeff)

Step 3: Look at intial data

  • good for deciding statistics to use.
print01Report(mydata)

# gives initial description of data 
# reading network variables , covariates, density measures/changes in networks, tie changes between subsequent observations... calculate how much networks changed over time. 
# dont use balance calculation 

Step 4: Add effects

Example:



net1g <- graph_from_adjacency_matrix(ts_net1, mode = "directed")
coords <- layout_(net1g, nicely())  #let us keep the layout
par(mar = c(0.1, 0.1, 0.1, 0.1))
{
    plot.igraph(net1g, layout = coords)
    graphics::box()
}

# for every actor, there are 10 options - each actor can break tie, keep tie/do nothing, or add new tie. If tie, can break or keep. If there is no tie, can remain 0 tie or form a tie. 


# Now, select 'random' agent: 
set.seed(24553253)
ego <- ts_select(net = ts_net1)
ego


#### Network: ts_net1, ego = ego4 (ego 4 allowed to make ministeps). package then will list all of the different adjacency matrices. Shows all of the different next ministep options for ego 4. 


#### 
options <- ts_alternatives_ministep(net = ts_net1, ego = ego)
options

plots <- lapply(options, graph_from_adjacency_matrix, mode = "directed")
par(mar = c(0, 0, 0, 0) + 0.1)
par(mfrow = c(2, 2))

fplot <- function(x) {
    plot.igraph(x, layout = coords, margin = 0)
    graphics::box()
}


ts_degree(net = options[[1]], ego = ego)
sapply(options, ts_degree, ego = ego)

IF NEEDED LATER:

Now, try to loop in gender

Make simple adj matrix for gender

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KMTcgT2N0b2JlciByZXZpZXcgDQoNCk5ldyBEYXRhIHJldmlldyA6ICJDOlxHaXRodWJcbGFiam91cm5hbFwyMDI1MTAxNnNjaG9sYXJzLlJkYSINCg0KIyBEYXRhIFByZXAgV29yayANCg0KIyMgQ2xlYXIgZGF0YQ0KYGBge3J9DQpybShsaXN0PWxzKCkpICNzdGFydCBjbGVhbg0KYGBgDQoNCiMjIExvYWQgRnVuY3Rpb25zDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShzZWxlbmlkZXIpDQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KG5ldHN0YXQpDQpsaWJyYXJ5KHBpbmdyKQ0KbGlicmFyeShqc29ubGl0ZSkNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkob3BlbmFsZXhSKQ0KDQoNCnBhY2thZ2VzIDwtIGMoInRpZHl2ZXJzZSIsICJzY2hvbGFyIiwgIm9wZW5hbGV4UiIsICJydmVzdCIsICJqc29ubGl0ZSIpDQpwYWNrYWdlcyA8LSBjKCJkZXZ0b29scyIsICJpZ3JhcGgiKQ0KDQpmcGFja2FnZS5jaGVjayA8LSBmdW5jdGlvbihwYWNrYWdlcykgew0KICAgIGxhcHBseShwYWNrYWdlcywgRlVOID0gZnVuY3Rpb24oeCkgew0KICAgICAgICBpZiAoIXJlcXVpcmUoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkgew0KICAgICAgICAgICAgaW5zdGFsbC5wYWNrYWdlcyh4LCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgICAgICAgICAgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQogICAgICAgIH0NCiAgICB9KQ0KfQ0KDQpmc2F2ZSA8LSBmdW5jdGlvbih4LCBmaWxlID0gTlVMTCwgbG9jYXRpb24gPSAiLi9kYXRhL3Byb2Nlc3NlZC8iKSB7DQogICAgaWZlbHNlKCFkaXIuZXhpc3RzKCJkYXRhIiksIGRpci5jcmVhdGUoImRhdGEiKSwgRkFMU0UpDQogICAgaWZlbHNlKCFkaXIuZXhpc3RzKCJkYXRhL3Byb2Nlc3NlZCIpLCBkaXIuY3JlYXRlKCJkYXRhL3Byb2Nlc3NlZCIpLCBGQUxTRSkNCiAgICBpZiAoaXMubnVsbChmaWxlKSkNCiAgICAgICAgZmlsZSA9IGRlcGFyc2Uoc3Vic3RpdHV0ZSh4KSkNCiAgICBkYXRlbmFtZSA8LSBzdWJzdHIoZ3N1YigiWzotXSIsICIiLCBTeXMudGltZSgpKSwgMSwgOCkNCiAgICB0b3RhbG5hbWUgPC0gcGFzdGUobG9jYXRpb24sIGZpbGUsICJfIiwgZGF0ZW5hbWUsICIucmRhIiwgc2VwID0gIiIpDQogICAgc2F2ZSh4LCBmaWxlID0gdG90YWxuYW1lKSAgI25lZWQgdG8gZml4IGlmIGZpbGUgaXMgcmVsb2FkZWQgYXMgaW5wdXQgbmFtZSwgbm90IGFzIHguIA0KfQ0KDQpmbG9hZCA8LSBmdW5jdGlvbihmaWxlbmFtZSkgew0KICAgIGxvYWQoZmlsZW5hbWUpDQogICAgZ2V0KGxzKClbbHMoKSAhPSAiZmlsZW5hbWUiXSkNCn0NCg0KZnNob3dkZiA8LSBmdW5jdGlvbih4LCAuLi4pIHsNCiAgICBrbml0cjo6a2FibGUoeCwgZGlnaXRzID0gMiwgImh0bWwiLCAuLi4pICU+JQ0KICAgICAgICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKSAlPiUNCiAgICAgICAga2FibGVFeHRyYTo6c2Nyb2xsX2JveCh3aWR0aCA9ICIxMDAlIiwgaGVpZ2h0ID0gIjMwMHB4IikNCn0NCg0KYGBgDQoNCg0KIyMgQWNjZXNzIGxhcmdlIGRhdGEgZmlsZSBvZiBwcm9mZXNzb3JzLCBzZXQgb2YgZWdvcyBmb3IgcmVzZWFyY2gNCg0KIyMjIExvYWQgRGF0YXNldCAtIG5ldyBkYXRhc2V0IGZyb20gSm9zDQoNCmBgYHtyfQ0Kc2Nob2xhcnMgPC0gZmxvYWQoIkM6L0dpdGh1Yi9sYWJqb3VybmFsLzIwMjUxMDE2c2Nob2xhcnMuUmRhIikgDQpgYGANCg0KDQojIyBOZXcgZmNvbG5ldCBmdW5jdGlvbg0KDQojIyMgRGVmaW5lIE5ldHdvcmsgRGF0YSBIZWxwZXIgRnVuY3Rpb24NCmBgYHtyfQ0KZmNvbG5ldCA9IGZ1bmN0aW9uKGRhdGEgPSBzY2hvbGFycywgdW5pdmVyc2l0eSA9IGMoIlJVIiwgJ1VVJyksIGRpc2NpcGxpbmUgPSAiU29jaW9sb2dpZSIsIHdhdmVzID0gbGlzdChjKDIwMTUsDQogICAgMjAxOCksIGMoMjAxOSwgMjAyMyksIGMoMjAyNCwgMjAyNSkpLCB0eXBlID0gYygiZmlyc3QiKSkgew0KDQogICAgdW5pdmVyc2l0eSA9IHBhc3RlMCgnKCcsIHBhc3RlMCh1bml2ZXJzaXR5LCBjb2xsYXBzZT0nfCcgKSwgJyknKQ0KICAgIGRpc2NpcGxpbmUgPSBwYXN0ZTAoJygnLCBwYXN0ZTAoZGlzY2lwbGluZSwgY29sbGFwc2U9J3wnICksICcpJykNCg0KICAgICMgc3RlcCAxDQogICAgZGVtb2dyYXBoaWNzID0gZGF0YSRkZW1vZ3JhcGhpY3MNCiAgICBzYW1wbGUgPSB3aGljaCgNCiAgICAgICAgKHN0cl9kZXRlY3QoZGVtb2dyYXBoaWNzJHVuaXZlcnNpdGVpdC4yMiwgdW5pdmVyc2l0eSkNCiAgICAgICAgICAgIHwgc3RyX2RldGVjdChkZW1vZ3JhcGhpY3MkdW5pdmVyc2l0ZWl0LjI0LCB1bml2ZXJzaXR5KQ0KICAgICAgICAgICAgfCBzdHJfZGV0ZWN0KGRlbW9ncmFwaGljcyR1bml2ZXJzaXRlaXQuMjUsIHVuaXZlcnNpdHkpDQogICAgICAgICkgJiAoDQogICAgICAgICAgICBzdHJfZGV0ZWN0KGRlbW9ncmFwaGljcyRkaXNjaXBsaW5lLjIyLCBkaXNjaXBsaW5lKQ0KICAgICAgICAgICAgfCBzdHJfZGV0ZWN0KGRlbW9ncmFwaGljcyRkaXNjaXBsaW5lLjI0LCBkaXNjaXBsaW5lKQ0KICAgICAgICAgICAgfCBzdHJfZGV0ZWN0KGRlbW9ncmFwaGljcyRkaXNjaXBsaW5lLjI1LCBkaXNjaXBsaW5lKQ0KICAgICAgICApIHw+IHJlcGxhY2VfbmEoRkFMU0UpKQ0KDQogICAgZGVtb2dyYXBoaWNzX3NvYyA9IGRlbW9ncmFwaGljc1tzYW1wbGUsIF0gfD4gZHJvcF9uYShpZCkNCg0KICAgICMgc3RlcCAyDQogICAgaWRzID0gZGVtb2dyYXBoaWNzX3NvYyRpZCB8PiB1bmlxdWUoKQ0KDQoNCiAgICBzY2hvbGFyc19zZWwgPSBsaXN0KCkgDQogICAgZm9yIChpZF8gaW4gaWRzKXsNCiAgICAgICAgc2Nob2xhcnNfc2VsW1tpZF9dXSA9IGJpbmRfcm93cyhzY2hvbGFycyR3b3JrcykgfD4NCiAgICAgICAgICAgIGZpbHRlcihhdXRob3JfaWQgPT0gaWRfKQ0KICAgIH0NCiAgICBzY2hvbGFyc19zZWwgPSBiaW5kX3Jvd3Moc2Nob2xhcnMkd29ya3MpIA0KICAgIA0KDQogICAgbndhdmVzID0gbGVuZ3RoKHdhdmVzKQ0KICAgIG5ldHMgPSBhcnJheSgwLCBkaW0gPSBjKG53YXZlcywgbGVuZ3RoKGlkcyksIGxlbmd0aChpZHMpKSwgZGltbmFtZXMgPSBsaXN0KHdhdmUgPSAxOm53YXZlcywgaWRzLA0KICAgICAgICBpZHMpKQ0KICAgIGRpbW5hbWVzKG5ldHMpDQoNCiAgICAjIHN0ZXAgMw0KICAgIGRmX3dvcmtzID0gdGliYmxlKA0KICAgICAgICAgICAgd29ya3NfaWQgPSBzY2hvbGFyc19zZWwkaWQsIA0KICAgICAgICAgICAgd29ya3NfYXV0aG9yID0gc2Nob2xhcnNfc2VsJGF1dGhvcnNoaXBzLCANCiAgICAgICAgICAgIHdvcmtzX3llYXIgPSBzY2hvbGFyc19zZWwkcHVibGljYXRpb25feWVhcg0KICAgICAgICApDQoNCg0KICAgIGRmX3dvcmtzID0gZGZfd29ya3NbIWR1cGxpY2F0ZWQoZGZfd29ya3MpLCBdDQoNCiAgICAjIHN0ZXAgNA0KICAgIGlmICh0eXBlID09ICJmaXJzdCIpIHsNCiAgICAgICAgZm9yIChqIGluIDE6bGVuZ3RoKHdhdmVzKSkgew0KICAgICAgICAgICAgZGZfd29ya3NfdyA9IGRmX3dvcmtzW2RmX3dvcmtzJHdvcmtzX3llYXIgPj0gd2F2ZXNbW2pdXVsxXSAmIGRmX3dvcmtzJHdvcmtzX3llYXIgPD0gd2F2ZXNbW2pdXVsyXSwNCiAgICAgICAgICAgICAgICBdDQogICAgICAgICAgICBmb3IgKGkgaW4gMTpucm93KGRmX3dvcmtzX3cpKSB7DQogICAgICAgICAgICAgICAgZWdvID0gZGZfd29ya3NfdyR3b3Jrc19hdXRob3JbaV1bWzFdXSRpZFsxXQ0KICAgICAgICAgICAgICAgIGFsdGVycyA9IGRmX3dvcmtzX3ckd29ya3NfYXV0aG9yW2ldW1sxXV0kaWRbLTFdDQogICAgICAgICAgICAgICAgaWYgKHN1bShpZHMgJWluJSBlZ28pID4gMCAmIHN1bShpZHMgJWluJSBhbHRlcnMpID4gMCkgew0KICAgICAgICAgICAgICAgICAgbmV0c1tqLCB3aGljaChpZHMgJWluJSBlZ28pLCB3aGljaChpZHMgJWluJSBhbHRlcnMpXSA9IDENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQogICAgICAgIH0NCiAgICB9DQoNCiAgICBpZiAodHlwZSA9PSAibGFzdCIpIHsNCiAgICAgICAgZm9yIChqIGluIDE6bGVuZ3RoKHdhdmVzKSkgew0KICAgICAgICAgICAgZGZfd29ya3NfdyA9IGRmX3dvcmtzW2RmX3dvcmtzJHdvcmtzX3llYXIgPj0gd2F2ZXNbW2pdXVsxXSAmIGRmX3dvcmtzJHdvcmtzX3llYXIgPD0gd2F2ZXNbW2pdXVsyXSwNCiAgICAgICAgICAgICAgICBdDQogICAgICAgICAgICBmb3IgKGkgaW4gMTpucm93KGRmX3dvcmtzX3cpKSB7DQogICAgICAgICAgICAgICAgZWdvID0gcmV2KGRmX3dvcmtzX3ckd29ya3NfYXV0aG9yW2ldW1sxXV0kaWRbMV0pDQogICAgICAgICAgICAgICAgYWx0ZXJzID0gcmV2KGRmX3dvcmtzX3ckd29ya3NfYXV0aG9yW2ldW1sxXV0kaWRbLTFdKQ0KICAgICAgICAgICAgICAgIGlmIChzdW0oaWRzICVpbiUgZWdvKSA+IDAgJiBzdW0oaWRzICVpbiUgYWx0ZXJzKSA+IDApIHsNCiAgICAgICAgICAgICAgICAgIG5ldHNbaiwgd2hpY2goaWRzICVpbiUgZWdvKSwgd2hpY2goaWRzICVpbiUgYWx0ZXJzKV0gPSAxDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQogICAgfQ0KICAgIGlmICh0eXBlID09ICJhbGwiKSB7DQogICAgICAgIGZvciAoaiBpbiAxOmxlbmd0aCh3YXZlcykpIHsNCiAgICAgICAgICAgIGRmX3dvcmtzX3cgPSBkZl93b3Jrc1tkZl93b3JrcyR3b3Jrc195ZWFyID49IHdhdmVzW1tqXV1bMV0gJiBkZl93b3JrcyR3b3Jrc195ZWFyIDw9IHdhdmVzW1tqXV1bMl0sDQogICAgICAgICAgICAgICAgXQ0KICAgICAgICAgICAgZm9yIChpIGluIDE6bnJvdyhkZl93b3Jrc193KSkgew0KICAgICAgICAgICAgICAgIGVnb3MgPSBkZl93b3Jrc193JHdvcmtzX2F1dGhvcltpXVtbMV1dJGlkDQogICAgICAgICAgICAgICAgaWYgKHN1bShpZHMgJWluJSBlZ29zKSA+IDApIHsNCiAgICAgICAgICAgICAgICAgIG5ldHNbaiwgd2hpY2goaWRzICVpbiUgZWdvcyksIHdoaWNoKGlkcyAlaW4lIGVnb3MpXSA9IDENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQogICAgICAgICAgICBkaWFnKG5ldHNbaiwsXSkgPSAwDQogICAgICAgIH0NCiAgICB9DQoNCiAgICBvdXRwdXQgPSBsaXN0KCkNCiAgICBvdXRwdXQkZGF0YSA9IGRlbW9ncmFwaGljc19zb2MNCiAgICBvdXRwdXQkbmV0cyA9IG5ldHMNCiAgICByZXR1cm4ob3V0cHV0KQ0KfQ0KYGBgDQoNCiMjIyBsb2FkIFJzaWVuYSBwYWNrYWdlcw0KYGBge3J9DQpwYWNrYWdlcyA9IGMoDQogICAgIlJTaWVuYSIsICJ0aWR5dmVyc2UiLA0KICAgICdkcGx5cicsICdzdHJpbmdyJyAjIHRoZXNlIHBhY2thZ2VzIHdlcmUgYWRkZWQgdG8gbWFrZSB0aGUgY29kZSBydW4NCikNCmZwYWNrYWdlLmNoZWNrKHBhY2thZ2VzKQ0KDQpgYGANCg0KDQojIEdldHRpbmcgRGF0YQ0KDQojIyBBcHBsaWNhdGlvbg0KDQojIyMgTG9hZCBEYXRhDQpgYGB7cn0NCiMgZnJvbSBKb3MgY29kZSAtIFJhZGJvdWQgYW5kIFV0cmVjaHQNCnRlc3QxID0gZmNvbG5ldChzY2hvbGFycywgdW5pdmVyc2l0eSA9IGMoJ1JVJywgJ1VVJykpIA0KZGZfZWdvMSA9IGJpbmRfcm93cyh0ZXN0MSRkYXRhKQ0KDQojIFJhZGJvdWQgb25seSAod2hlcmUgSSB3YW50IHRvIHN0YXJ0KQ0KdGVzdCA9IGZjb2xuZXQoc2Nob2xhcnMsIHVuaXZlcnNpdHkgPSBjKCJSVSIpKSAjb25seSBSYWRib3VkIA0KZGZfZWdvID0gYmluZF9yb3dzKHRlc3QkZGF0YSkNCmBgYA0KDQojIyMgV3JhbmdsZSBEYXRhDQpgYGB7cn0NCndhdmUxID0gdGVzdCRuZXRzWzEsLF0NCndhdmUyID0gdGVzdCRuZXRzWzIsLF0NCndhdmUzID0gdGVzdCRuZXRzWzMsLF0NCg0KbmV0cyA9IGFycmF5KA0KICAgIGRhdGEgPSBjKHdhdmUxLCB3YXZlMiwgd2F2ZTMpLA0KICAgIGRpbSA9IGMoZGltKHdhdmUyKSwgMikNCikNCg0KbmV0ID0gc2llbmFEZXBlbmRlbnQobmV0cykNCmBgYA0KDQoNCiMjIElzb2xhdGUgR2VuZGVyIHZhcmlhYmxlIChiaW5hcnkpDQoNCmBgYHtyfQ0KIyBFeGFtcGxlIGZyb20gcmVjb2RpbmcgZnVuY3Rpb24NCiNkZl9lZ28gPSBkZl9lZ28gfD4NCiMgICAgbXV0YXRlKA0KIyAgICAgICAgZnVuY3MgPSBjYXNlX3doZW4oDQojICAgICAgICAgICAgZnVuY3RpZS4yMiA9PSAiRnVsbCBQcm9mZXNzb3IiIH4gMSwNCiMgICAgICAgICAgICBmdW5jdGllLjI0ID09ICJGdWxsIFByb2Zlc3NvciIgfiAxLA0KIyAgICAgICAgICAgIGZ1bmN0aWUuMjUgPT0gIkZ1bGwgUHJvZmVzc29yIiB+IDEsDQojICAgICAgICAgICAgLmRlZmF1bHQgPSAwDQojICAgICAgICApDQojICAgICkNCg0KIyBSZWNvZGluZyBmb3IgZ2VuZGVyDQpkZl9lZ28gPSBkZl9lZ28gfD4NCiAgICBtdXRhdGUoDQogICAgICAgIGZlbWFsZSA9IGNhc2Vfd2hlbigNCiAgICAgICAgICAgIGdlbmRlciA9PSAiZmVtYWxlIiB+IDEsDQogICAgICAgICAgICAuZGVmYXVsdCA9IDANCiAgICAgICAgKQ0KICAgICkNCmZlbWFsZSA9IGNvQ292YXIoZGZfZWdvJGZlbWFsZSkNCmBgYA0KDQoNCg0KIyMgVmlzdWFsaXppbmcgUlUgV2F2ZXMNCg0KYGBge3J9DQojIG1ha2UgYWRqYWNlbmN5IG1hdHJpeCB3aXRoIGZpcnN0IHdhdmUgb2YgZGF0YQ0KdGVzdF93YXZlMXJ1IDwtIGlncmFwaDo6Z3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KA0KICB0ZXN0JG5ldHNbMSwsXSwgI2ZvciB0aGlzIGV4YW1wbGUgSSB0YWtlIHRoZSBmaXJzdCB3YXZlIG9mIGRhdGEuICh0aHVzIEkgc2VsZWN0IHRoZSBhcnJheSBvZiBuZXR3b3JrcyBhbmQgdGFrZSB0aGUgZmlyc3QgbWF0cml4KQ0KICBtb2RlID0gYygiZGlyZWN0ZWQiKSwNCiAgd2VpZ2h0ZWQgPSBOVUxMLA0KICBkaWFnID0gRkFMU0UsDQogIGFkZC5jb2xuYW1lcyA9IE5VTEwsDQogIGFkZC5yb3duYW1lcyA9IE5VTEwNCikNCg0KI3Bsb3QgdG8gc2VlIGlmIGl0IHdvcmtlZCANCnBsb3QodGVzdF93YXZlMXJ1LA0KICB2ZXJ0ZXguY29sb3IgPSBpZmVsc2UoZGZfZWdvJGZlbWFsZSA9PSAxLCAicmVkIiwgImJsdWUiKSwNCiAgdmVydGV4LmxhYmVsID0gTkEsDQogIGVkZ2Uud2lkdGggPSAwLjIsDQogIGVkZ2UuYXJyb3cuc2l6ZSA9MC4yKQ0KDQpkaW0odGVzdF93YXZlMXJ1KSAjY2hlY2sgaXQgd29ya3MgDQpzdW0oaXMubmEodGVzdF93YXZlMXJ1KSkgI2NoZWNrIGl0IGlzIGNvbXBsZXRlIC0tIGlmIDAgbWlzc2luZyB2YWx1ZXMNCg0KYGBgDQoNCg0KIyMgVmlzdWFsaXppbmcganVzdCByYWRib3VkIChib3RoIGRlcHRzKSB3YXZlIDINCmBgYHtyfQ0KdGVzdF93YXZlMnJ1IDwtIGlncmFwaDo6Z3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KA0KICB0ZXN0JG5ldHNbMiwsXSwgI2ZvciB0aGlzIGV4YW1wbGUgSSB0YWtlIHRoZSBmaXJzdCB3YXZlIG9mIGRhdGEuICh0aHVzIEkgc2VsZWN0IHRoZSBhcnJheSBvZiBuZXR3b3JrcyBhbmQgdGFrZSB0aGUgZmlyc3QgbWF0cml4KQ0KICBtb2RlID0gYygiZGlyZWN0ZWQiKSwNCiAgd2VpZ2h0ZWQgPSBOVUxMLA0KICBkaWFnID0gRkFMU0UsDQogIGFkZC5jb2xuYW1lcyA9IE5VTEwsDQogIGFkZC5yb3duYW1lcyA9IE5VTEwNCikNCg0KI3Bsb3QgdG8gc2VlIGlmIGl0IHdvcmtlZCANCnBsb3QodGVzdF93YXZlMnJ1LA0KICB2ZXJ0ZXguY29sb3IgPSBpZmVsc2UoZGZfZWdvJGZlbWFsZSA9PSAxLCAicmVkIiwgImJsdWUiKSwNCiAgdmVydGV4LmxhYmVsID0gTkEsDQogIGVkZ2Uud2lkdGggPSAwLjIsDQogIGVkZ2UuYXJyb3cuc2l6ZSA9MC4yKQ0KYGBgDQoNCg0KYGBge3J9DQp0ZXN0X3dhdmUzcnUgPC0gaWdyYXBoOjpncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgoDQogIHRlc3QkbmV0c1szLCxdLCAjZm9yIHRoaXMgZXhhbXBsZSBJIHRha2UgdGhlIGZpcnN0IHdhdmUgb2YgZGF0YS4gKHRodXMgSSBzZWxlY3QgdGhlIGFycmF5IG9mIG5ldHdvcmtzIGFuZCB0YWtlIHRoZSBmaXJzdCBtYXRyaXgpDQogIG1vZGUgPSBjKCJkaXJlY3RlZCIpLA0KICB3ZWlnaHRlZCA9IE5VTEwsDQogIGRpYWcgPSBGQUxTRSwNCiAgYWRkLmNvbG5hbWVzID0gTlVMTCwNCiAgYWRkLnJvd25hbWVzID0gTlVMTA0KKQ0KDQojcGxvdCB0byBzZWUgaWYgaXQgd29ya2VkIA0KcGxvdCh0ZXN0X3dhdmUzcnUsDQogIHZlcnRleC5jb2xvciA9IGlmZWxzZShkZl9lZ28kZmVtYWxlID09IDEsICJyZWQiLCAiYmx1ZSIpLA0KICB2ZXJ0ZXgubGFiZWwgPSBOQSwNCiAgZWRnZS53aWR0aCA9IDAuMiwNCiAgZWRnZS5hcnJvdy5zaXplID0wLjIpDQpgYGANCg0KDQojIEFkZCBpbiBjb2xsYWJvcmF0b3JzICsgdGhlaXIgZ2VuZGVyPw0KYGBge3J9DQpgYGANCg0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KDQojIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MNCiMjIE5PVyAtIExPT0sgQVQgREVTQ1JJUFRJVkUgU1RBVElTVElDUyBGT1IgUlUgT05MWSANCg0KYGBge3J9DQoNCnJlcXVpcmUoaWdyYXBoKQ0KDQpwYWNrYWdlcyA8LSBjKCJ0aWR5dmVyc2UiLCAic2Nob2xhciIsICJvcGVuYWxleFIiLCAicnZlc3QiLCAianNvbmxpdGUiKQ0KcGFja2FnZXMgPC0gYygiZGV2dG9vbHMiLCAiaWdyYXBoIikNCg0KI1NJWkUNCiMgbnVtYmVyIG9mIG5vZGVzIGZvciBSVSBwcm9mZXNzb3JzDQp2Y291bnQodGVzdF93YXZlMXJ1KSAjcmV0dXJucyAxNjANCnZjb3VudCh0ZXN0X3dhdmUycnUpICNyZXR1cm5zIDE2MA0KdmNvdW50KHRlc3Rfd2F2ZTNydSkgI3JldHVybnMgMTYwIA0KDQojU0laRSAtIGZvciByZWZlcmVuY2UNCiMgbnVtYmVyIG9mIG5vZGVzIGZvciBhbGwgcHJvZmVzc29ycw0KI3Zjb3VudCh0ZXN0X3cxKSAjcmV0dXJucyA2NzQNCiN2Y291bnQodGVzdF93MikgI3JldHVybnMgNjc0DQoNCg0KI0VER0VTDQojIG51bWJlciBvZiBlZGdlcyBmb3IgUlUgcHJvZmVzc29ycw0KZWNvdW50KHRlc3Rfd2F2ZTFydSkgI3JldHVybnMgNDkNCmVjb3VudCh0ZXN0X3dhdmUycnUpICNyZXR1cm5zIDEzOA0KZWNvdW50KHRlc3Rfd2F2ZTNydSkgI3JldHVybnMgNzUNCg0KDQojREVHUkVFDQojIGxvb2tpbmcgYXQgY2x1c3RlcmluZyBhbmQgc3ByZWFkDQppZ3JhcGg6OmRlZ3JlZSh0ZXN0X3dhdmUxcnUpDQppZ3JhcGg6OmRlZ3JlZSh0ZXN0X3dhdmUycnUpDQppZ3JhcGg6OmRlZ3JlZSh0ZXN0X3dhdmUzcnUpDQoNCg0KaGlzdCh0YWJsZShkZWdyZWUodGVzdF93YXZlMXJ1KSksIHhsYWI9J2luZGVncmVlJywgbWFpbj0gJ0hpc3RvZ3JhbSBvZiBpbmRlZ3JlZScpIA0KIyBldmVyeSBudW1iZXIgaXMgdGhlIGRlZ3JlZSBsZXZlbCBvZiBlYWNoIGFjdG9yIC0tIGFuZCBzZWUgaXQgaXMgaGVhdmlseSBza2V3ZWQgdG8gdGhlIGxlZnQNCiMgV2F2ZSAxOiBzZWUgZnJlcXVlbmN5IG9mIDcgZm9yIGluZGVncmVlIDA6NTAsIGZyZXF1ZW5jeSBvZiAwIGZvciBpbmRlZ3JlZSA1MDoxMDAsIGZyZXF1ZW5jeSAxIGZvciBpbmRlZ3JlZSAxMDA6MTUwDQoNCmhpc3QodGFibGUoZGVncmVlKHRlc3Rfd2F2ZTJydSkpLCB4bGFiPSdpbmRlZ3JlZScsIG1haW49ICdIaXN0b2dyYW0gb2YgaW5kZWdyZWUnKSAjIGV2ZXJ5IG51bWJlciBpcyB0aGUgZGVncmVlIGxldmVsIG9mIGVhY2ggYWN0b3IgLS0gYW5kIHNlZSBpdCBpcyBoZWF2aWx5IGxlZnQgc2tld2VkIHRvbyAgDQojIFdhdmUgMjogc2VlIGZyZXF1ZW5jeSBvZiAxMCBmb3IgaW5kZWdyZWUgMDoyMCwgZnJlcXVlbmN5IG9mIDIgZm9yIGluZGVncmVlIDIwOjQwLCAwIGZvciA0MDo2MCwgMSBmb3IgNjA6ODANCg0KaGlzdCh0YWJsZShkZWdyZWUodGVzdF93YXZlM3J1KSksIHhsYWI9J2luZGVncmVlJywgbWFpbj0gJ0hpc3RvZ3JhbSBvZiBpbmRlZ3JlZScpICMgZXZlcnkgbnVtYmVyIGlzIHRoZSBkZWdyZWUgbGV2ZWwgb2YgZWFjaCBhY3RvciAtLSBhbmQgc2VlIGl0IGlzIGhlYXZpbHkgbGVmdCBza2V3ZWQgdG9vICANCiMgV2F2ZSAzOiBzZWUgZnJlcXVlbmN5IG9mIDQgZm9yIGluZGVncmVlIDA6MjAsIGZyZXF1ZW5jeSBvZiAyIGZvciBpbmRlZ3JlZSAyMDo0MCwgMCBmb3IgNDA6ODAsIDEgZm9yIDgwOjEwMA0KDQoNCiNUUkFOU0lUSVZJVFkgLS0gYWxsIG9mIHRoZXNlIHJldHVybiAiTkFOIiAtLSBjaGVjaz8NCiMgZGlyZWN0ZWQ6IGJlIGF3YXJlIHRoYXQgZGlyZWN0ZWQgZ3JhcGhzIGFyZSBjb25zaWRlcmVkIGFzIHVuZGlyZWN0ZWQuIENIRUNLIElGIFRFU1RfVzEgQU5EIDIgQVJFIERJUkVDVEVEIE9SIFVORElSRUNURUQuDQojIyBGTEFHIC0gRVJST1IgV0lUSCBUSElTIC0gTk9UIEFCTEUgVE8gUkVBTExZIFVTRS9WSUVXIFJFU1VMVFMNCmlncmFwaDo6dHJhbnNpdGl2aXR5KHRlc3Rfd2F2ZTFydSwgdHlwZSA9IGMoImxvY2FsdW5kaXJlY3RlZCIpLCBpc29sYXRlcyA9IGMoIk5hTiIsICJ6ZXJvIikpICNkaWZmZXJlbmNlcyBwb3Agb3V0IGxlc3MgDQppZ3JhcGg6OnRyYW5zaXRpdml0eSh0ZXN0X3dhdmUycnUsIHR5cGUgPSBjKCJsb2NhbHVuZGlyZWN0ZWQiKSwgaXNvbGF0ZXMgPSBjKCJOYU4iLCAiemVybyIpKSAjZGlmZmVyZW5jZXMgcG9wIG91dCBsZXNzIA0KaWdyYXBoOjp0cmFuc2l0aXZpdHkodGVzdF93YXZlM3J1LCB0eXBlID0gYygibG9jYWx1bmRpcmVjdGVkIiksIGlzb2xhdGVzID0gYygiTmFOIiwgInplcm8iKSkgI2RpZmZlcmVuY2VzIHBvcCBvdXQgbGVzcyANCg0KDQojQkVUV0VFTk5FU1MNCiMgZGlyZWN0ZWQ6IGJlIGF3YXJlIHRoYXQgZGlyZWN0ZWQgZ3JhcGhzIGFyZSBjb25zaWRlcmVkIGFzIHVuZGlyZWN0ZWQuIENIRUNLIElGIFRFU1RfVzEgQU5EIDIgQVJFIERJUkVDVEVEIE9SIFVORElSRUNURUQuDQppZ3JhcGg6OnRyYW5zaXRpdml0eSh0ZXN0X3dhdmUxcnUsIHR5cGUgPSBjKCJsb2NhbHVuZGlyZWN0ZWQiKSwgaXNvbGF0ZXMgPSBjKCJOYU4iLCAiemVybyIpKQ0KaWdyYXBoOjp0cmFuc2l0aXZpdHkodGVzdF93YXZlMnJ1LCB0eXBlID0gYygibG9jYWx1bmRpcmVjdGVkIiksIGlzb2xhdGVzID0gYygiTmFOIiwgInplcm8iKSkNCmlncmFwaDo6dHJhbnNpdGl2aXR5KHRlc3Rfd2F2ZTNydSwgdHlwZSA9IGMoImxvY2FsdW5kaXJlY3RlZCIpLCBpc29sYXRlcyA9IGMoIk5hTiIsICJ6ZXJvIikpDQoNCmBgYA0KDQoNCg0KIyMgTmV4dCwgbW92aW5nIGZyb20gbG9jYWwgdG8gZ2xvYmFsIHRyYW5zaXRpdml0eSANCi0gICBMb29rIGF0IHRyaWFkcyBmb3IgbW9yZSBnbG9iYWwgdHJhbnNpdGl2aXR5LiANCi0gICBOb3RlOiBHbG9iYWwgPSBudW1iZXIgb2Ygb2JzZXJ2ZWQgb3ZlciBwb3NzaWJsZSAtIGNhbiBpZGVudGlmeSBhbGwgdHJhbnNpdGl2ZSB0cmlhZHMgYW5kIGFsbCBwb3NzaWJsZSB0cmlhZHMgDQotICAgUmV2aWV3aW5nIGR5YWRzIC0gdGhlbiB0cmlhZHMuIFNpbmNlIGl0IGlzIHVuZGlyZWN0ZWQsIGl0IGlzIGxlc3MgZGlmZmljdWx0IHRvIGNhbGN1bGF0ZS4gDQotICAgTm93LCBsb29raW5nIGF0IHRyaWFkIGNlbnN1cyB2cyB0cmlhZCBhbGxlZ2F0aW9uDQoNCmBgYHtyfQ0KIyBwbG90OiBpZ3JhcGggLSBYWCA8LSBtYWtlX2dyYXBoKHkpIDwtIHRlc3QkbmV0c1sxLCxdID8/DQojIGFkaiBtYXQ6IFhYIDwtIGFzX2Fkal9tYXRyaXgoKHBsb3QpLCB0eXBlID0gImJvdGgiLCBzcGFyc2UgPSBGQUxTRSkgLS0gYWRqIG1hdCA9IHRlc3RfdzEgPSAgdGVzdCRuZXRzWzEsLF0NCg0KDQppZ3JhcGg6OmR5YWQuY2Vuc3VzKHRlc3Rfd2F2ZTFydSkgI3dpdGggcGxvdCAtLSB3b3JrcyANCiAgIyBSZXR1cm5zOiA3IG11dCwgMzUgYXN5bSwgMTI2NzggbnVsbCANCmlncmFwaDo6ZHlhZC5jZW5zdXModGVzdF93YXZlMnJ1KSAjd2l0aCBwbG90IC0tIHdvcmtzDQogICMgUmV0dXJuczogMTMgbXV0LCAxMTIgYXN5bSwgMTI1NzUgbnVsbCANCmlncmFwaDo6ZHlhZC5jZW5zdXModGVzdF93YXZlM3J1KSAjd2l0aCBwbG90IC0tIHdvcmtzDQogICMgUmV0dXJuczogMyBtdXQsIDY5IGFzeW0sIDEyNjQ4IG51bGwgDQoNCg0KaWdyYXBoOjp0cmlhZC5jZW5zdXModGVzdF93YXZlMXJ1KSAjd2l0aCBwbG90IC0tIHdvcmtzDQogICMgUmV0dXJuczogIFsxXSA2NjMzNjQgICA1NDA1ICAgMTA3NiAgICAgMTEgICAgIDI0ICAgICAxMSAgICAgMTUgICAgICA2ICAgICAgMiAgICAgIDAgICAgICAzICAgICAgMyAgICAgIDAgICAgICAwICAgICAgMCAgICAgIDANCg0KaWdyYXBoOjp0cmlhZC5jZW5zdXModGVzdF93YXZlMnJ1KSAjd2l0aCBwbG90IC0tIHdvcmtzDQogICMgUmV0dXJuczogICBbMV0gNjUwNTg3ICAxNjk4NiAgIDE5NjMgICAgIDM3ICAgIDE4OSAgICAgNTggICAgIDU2ICAgICAxMCAgICAgMTQgICAgICAwICAgICAgMSAgICAgIDggICAgICA0ICAgICAgNCAgICAgIDIgICAgICAxDQoNCmlncmFwaDo6dHJpYWQuY2Vuc3VzKHRlc3Rfd2F2ZTNydSkgI3dpdGggcGxvdCAtLSB3b3Jrcw0KICAjIFJldHVybnM6ICAgWzFdIDY1ODY3NSAgMTA2NTggICAgNDYyICAgICAyOCAgICAgNjggICAgIDEzICAgICAgOCAgICAgIDIgICAgICA1ICAgICAgMCAgICAgIDAgICAgICAwICAgICAgMCAgICAgIDAgICAgICAxICAgICAgMA0KDQoNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCmxpYnJhcnkoc25hKQ0KDQojIFdhdmUgMQ0Kc25hOjp0cmlhZC5jZW5zdXModGVzdCRuZXRzWzEsLF0pICN3aXRoIGFkaiBtYXRyaXggb2YgdGVzdF93YXZlMXJ1IC0tIHRyaWFkLmNlbnN1cyBvZiAodGVzdF93MSkgZG9lc24ndCB3b3JrLiANCnVubG9hZE5hbWVzcGFjZSgic25hIikgICNkZXRhY2ggdGhpcyBwYWNrYWdlIGFnYWluIHRvIGF2b2lkIGludGVyZmVyZW5jZSB3aXRoIG90aGVyIGlncmFwaCBmdW5jdGlvbnMgDQogICMgUmV0dXJuczogICAgICAgICAwMDMgIDAxMiAgMTAyICAgMDIxRCAwMjFVIDAyMUMgMTExRCAxMTFVIDAzMFQgMDMwQyAyMDEgMTIwRCAxMjBVIDEyMEMgMjEwIDMwMA0KICAgICAgICAgICAjIFsxLF0gNjYzMzY0ICA1NDA1IDEwNzYgIDExICAgMjQgICAxMSAgIDE1ICAgIDYgICAgMiAgICAwICAgMyAgICAzICAgIDAgICAgMCAgIDAgICAwDQogICMgU2FtZSBhcyBpZ3JhcGggdHJpYWQgY2Vuc3VzISANCg0KDQppZ3JhcGg6OnRyYW5zaXRpdml0eSh0ZXN0X3dhdmUxcnUsIHR5cGUgPSAiZ2xvYmFsIikgI3dpdGggcGxvdA0KICAjIFJldHVybnM6IFsxXSAwLjE3NjQ3MDYNCnNuYTo6Z3RyYW5zKHRlc3QkbmV0c1sxLCxdKSAjdHJpYWQgY2Vuc3VzIGEgZGlmZmVyZW50IHdheSwgYnV0IHRoaXMgaXMgd2l0aCBwbG90IC0gbmVlZCB3aXRoIGFkaiBtYXQ6DQogICMgUmV0dXJuczogWzFdIDAuMTczOTEzDQogICMjIFByZXYgQ29kZTogc25hOjpndHJhbnModGVzdCRuZXRzWzEsLF0pICN3aXRoIGFkaiBtYXRyaXgNCg0KdHJpYWRfdzFydSA8LSBkYXRhLmZyYW1lKHNuYTo6dHJpYWQuY2Vuc3VzKHRlc3QkbmV0c1sxLCxdKSkgI3NhdmUgYXMgZGYsICN3aXRoIGFkaiBtYXRyaXgNCg0KdHJhbnNpdGl2aXR5X3cxIDwtICgzICogdHJpYWRfdzFydSRYMzAwKS8odHJpYWRfdzFydSRYMjAxICsgMyAqIHRyaWFkX3cxcnUkWDMwMCkgI1gzMDAgaXMgdmFyaWFibGUgZm9yIHRyYW5zaXRpdmUgdHJpYWQgKHRoZSBmdWxseSBjbG9zZWQgdHJpYWQpIC0gd2UgbXVsdGlwbHkgYnkgMyBiZWNhdXNlIHRoZXJlIGFyZSAzIHBvc3NpYmxlIHRyYW5zaXRpdmUgdHJpYWRzDQoNCnRyYW5zaXRpdml0eV93MQ0KICAjIFJldHVybnMgMCAoPykNCg0KDQoNCg0KIyBXYXZlIDINCnNuYTo6dHJpYWQuY2Vuc3VzKHRlc3QkbmV0c1syLCxdKQ0KdW5sb2FkTmFtZXNwYWNlKCJzbmEiKSAgI0kgd2lsbCBkZXRhY2ggdGhpcyBwYWNrYWdlIGFnYWluDQoNCnRyaWFkX3cycnUgPC0gZGF0YS5mcmFtZShzbmE6OnRyaWFkLmNlbnN1cyh0ZXN0JG5ldHNbMiwsXSkpICNzYXZlIGFzIGRmDQoNCg0KaWdyYXBoOjp0cmFuc2l0aXZpdHkodGVzdF93YXZlMnJ1LCB0eXBlID0gImdsb2JhbCIpDQogICMgUmV0dXJuczogWzFdIDAuMjINCnNuYTo6Z3RyYW5zKHRlc3QkbmV0c1syLCxdKSAjdHJpYWQgY2Vuc3VzIGEgZGlmZmVyZW50IHdheSANCiAgIyBSZXR1cm5zOiBbMV0gMC4yODQyMTA1DQoNCnRyYW5zaXRpdml0eV93MiA8LSAoMyAqIHRyaWFkX3cycnUkWDMwMCkvKHRyaWFkX3cycnUkWDIwMSArIDMgKiB0cmlhZF93MnJ1JFgzMDApICNYMzAwIGlzIHZhcmlhYmxlIGZvciB0cmFuc2l0aXZlIHRyaWFkICh0aGUgZnVsbHkgY2xvc2VkIHRyaWFkKQ0KIyB3ZSBtdWx0aXBseSBieSAzIGJlY2F1c2UgdGhlcmUgYXJlIDMgcG9zc2libGUgdHJhbnNpdGl2ZSB0cmlhZHMNCnRyYW5zaXRpdml0eV93Mg0KICAjIFJldHVybnM6IFsxXSAwLjc1DQoNCg0KDQojIFdhdmUgMw0Kc25hOjp0cmlhZC5jZW5zdXModGVzdCRuZXRzWzMsLF0pDQogICAjIFJldHVybnM6IDAwMyAgICAwMTIgICAxMDIgICAwMjFEICAwMjFVICAwMjFDICAxMTFEICAxMTFVICAwMzBUICAwMzBDIDIwMSAgMTIwRCAgMTIwVSAxMjBDICAyMTAgIDMwMA0KICAgIyAgICBbMSxdICA2NTg2NzUgMTA2NTggNDYyICAgMjggICAgNjggICAgMTMgICAgIDggICAgIDIgICAgIDUgICAgMCAgICAwICAgIDAgICAgIDAgICAgIDAgICAgIDEgICAwDQoNCnVubG9hZE5hbWVzcGFjZSgic25hIikgICNJIHdpbGwgZGV0YWNoIHRoaXMgcGFja2FnZSBhZ2Fpbg0KDQp0cmlhZF93M3J1IDwtIGRhdGEuZnJhbWUoc25hOjp0cmlhZC5jZW5zdXModGVzdCRuZXRzWzMsLF0pKSAjc2F2ZSBhcyBkZg0KDQoNCmlncmFwaDo6dHJhbnNpdGl2aXR5KHRlc3Rfd2F2ZTNydSwgdHlwZSA9ICJnbG9iYWwiKQ0KICAjIFJldHVybnM6IFsxXSAwLjEzMTM4NjkNCnNuYTo6Z3RyYW5zKHRlc3QkbmV0c1szLCxdKSAjdHJpYWQgY2Vuc3VzIGEgZGlmZmVyZW50IHdheSANCiAgIyBSZXR1cm5zOiBbMV0gMC4yNQ0KDQp0cmFuc2l0aXZpdHlfdzMgPC0gKDMgKiB0cmlhZF93M3J1JFgzMDApLyh0cmlhZF93M3J1JFgyMDEgKyAzICogdHJpYWRfdzNydSRYMzAwKSAjWDMwMCBpcyB2YXJpYWJsZSBmb3IgdHJhbnNpdGl2ZSB0cmlhZCAodGhlIGZ1bGx5IGNsb3NlZCB0cmlhZCkNCiMgd2UgbXVsdGlwbHkgYnkgMyBiZWNhdXNlIHRoZXJlIGFyZSAzIHBvc3NpYmxlIHRyYW5zaXRpdmUgdHJpYWRzDQp0cmFuc2l0aXZpdHlfdzMNCiAgIyBSZXR1cm5zOiBbMV0gTmFODQoNCmBgYA0KDQpORUVEIFRPIElOQ0xVREUgVFJJQURTIC0gVFJBTlNJVElWSVRZIA0KT1VUREVHUkVFIEFORCBSRUNJUFJPQ0lUWSBBUkUgQUxXQVlTIElOIFRIRVJFLCBBTFNPIE5FRUQgT1VUREVHUkVFIEFDVElWSVRZIE9SIElOIERFR1JFRSBQT1BVTEFSSVRZLiBBTFNPIE5FRUQgU09NRVRISU5HIEZPUiBUUkFOU0lUSVZJVFkgLSBHV0VTUCBWQVJJQUJMRSBBTkQgRUZGRUNUUyBUTyBJTkNMVURFIC0gTUFLRSBTVVJFIFRPIElOQ0xVREUgT05FIE9GIFRIRVNFIFRPTy4NCg0KDQoNCiMjIE5ldHdvcmsgdmlzdWFsaXNhdGlvbjogTGV04oCZcyBtYWtlIHNpemUgcHJvcG9ydGlvbmFsIHRvIGJldHdlZW5uZXNzIHNjb3JlDQpgYGAge3J9DQojIGNoYW5naW5nIFYgb2YgV2F2ZTENClYodGVzdF93YXZlMXJ1KSRzaXplID0gYmV0d2Vlbm5lc3ModGVzdF93YXZlMXJ1LCBub3JtYWxpemVkID0gVCwgZGlyZWN0ZWQgPSBGQUxTRSkgKiA2MCArIDEwICAjYWZ0ZXIgc29tZSB0cmlhbCBhbmQgZXJyb3INCg0KDQogIyMgbXVsdGlwbGljYXRpb24gLSBjaGFuZ2luZyA2MCBjaGFuZ2VzIHRoZSBkaWZmZXJlbmNlIGluIHNpemUsLCBhZGRpbmcgMTAgbWFrZXMgdGhlIHNtYWxsZXN0IHZpc2libGUNCnBsb3QodGVzdF93YXZlMXJ1LCBtb2RlID0gInVuZGlyZWN0ZWQiKQ0KICMjIHN0dWNrOiBuZWVkIHRvIHJlbW92ZSBpZHMNCg0KDQojIGlncmFwaCwgd2FudCBubyBvdmVybGFwOiBpZ3JhcGggcGxvdHRpbmcgbm8gb3ZlcmxhcCAtLSBhIGxvdCBvZiBsYXlvdXQgZnVuY3Rpb25zIC0tIHdhbnQgdG8gaG9sZCBwcmludGluZyBkZXZpY2UgY29uc3RhbnQsIGFuZCB0aGVuIHJlZHVjZSBvdmVybGFwLi4udGhlIGlkZWEgaXMgdG8gcHVzaCBsZWFzdCBjZW50cmFsIGVnb3Mgb3V0IA0KDQpzZXQuc2VlZCgyMzQ1KQ0KbCA8LSBsYXlvdXRfd2l0aF9tZHModGVzdF93YXZlMXJ1KSAgI2h0dHBzOi8vaWdyYXBoLm9yZy9yL2RvYy9sYXlvdXRfd2l0aF9tZHMuaHRtbA0KcGxvdCh0ZXN0X3dhdmUxcnUsIGxheW91dCA9IGwpDQojIHN0b3J5IGluIHNlY29uZCBwbG90OiA1IGNsdXN0ZXJzID8gKGFyb3VuZCBYWCwgWFgsIFhYLCBYWCwgYW5kIFhYKSAtIGFuZCBpbi1iZXR3ZWVuICh3aGljaCB3YXNuJ3QgYXMgY2xlYXIgYmVmb3JlKQ0KICMjIHN0dWNrOiBuZWVkIHRvIHJlbW92ZSBpZHMNCg0KDQojTk9URTogUkVGIExBQiA0IFRPIE1PRElGWSBUSEUgVEhFIFNJWklORy9BUFBFQVJBTkNFIE9GIFRIRSBORVRXT1JLIFZJU1VBTFMNCg0KYGBgDQoNCg0KDQoNCiMgUnNpZW5hIHdvcmsgDQoNCiMjIEdldCBwYWNrYWdlczogSm9jaGVtJ3MgdHdvc3RlcA0KDQpgYGB7cn0NCnBhY2thZ2VzID0gYygiUlNpZW5hIiwgImRldnRvb2xzIiwgImlncmFwaCIpDQpmcGFja2FnZS5jaGVjayhwYWNrYWdlcykNCiMjIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YignSm9jaGVtVG9sc21hL1JzaWVuYVR3b1N0ZXAnLCBidWlsZF92aWduZXR0ZXM9VFJVRSkNCnBhY2thZ2VzID0gYygiUnNpZW5hVHdvU3RlcCIpDQpmcGFja2FnZS5jaGVjayhwYWNrYWdlcykNCmBgYA0KIyMgU3RlcCAxOiBEZWZpbmUgZGF0YQ0KSW5kZXBlbmRlbnQgdmFyaWFibGU6IGdlbmRlcj8NCg0KV2UgYWxyZWFkeSBrbm93OiBuZXQgPC0gc2llbmFEZXBlbmRlbnQobmV0cykgKGRlcGVuZGVudCB2YXJpYWJsZSkNCiAgRGVwZW5kZW50IHZhcmlhYmxlOiB0aWVzID0gW25ldF0NCg0KDQpgYGB7cn0NCg0KIyBuZXQxIDwtIHNpZW5hRGVwZW5kZW50KGFycmF5KGModGVzdF93YXZlMXJ1LCB0ZXN0X3dhdmUycnUsIHRlc3Rfd2F2ZTNydSkpKQ0KIyBmZW1hbGUgPC0gdmFyQ292YXIoZGZfZWdvJGZlbWFsZSkNCg0KIyBteWRhdGEgPC0gc2llbmFEYXRhQ3JlYXRlKG5ldCwgZ2VuZGVyLCApDQojIEFMUkVBRFkgQ09ERUQ6IA0KIyBuZXQgPC0gc2llbmFEZXBlbmRlbnQobmV0cykgI2RlcGVuZGVudCB2YXJpYWJsZSANCg0KIyBmZW1hbGUgPSBjb0NvdmFyKGRmX2VnbyRmZW1hbGUpICMgYXQgYWN0b3IgbGV2ZWwgLSBtZWFuIGNlbnRlcmVkIC0gaXMgYSB0aW1lIGNvbnN0YW50IGNvVmFyaWF0ZQ0KDQoNCg0KIyBOT1c6DQojIGNvbWJpbmUgaW50byBkYXRhc2V0IC0gaWYgdXNlIFJzaWVuYSwgbmVlZCB0aGlzLg0KIyBnZW5kZXINCmdlbmRlciA8LSBhcy5udW1lcmljKGRmX2VnbyRnZW5kZXIgPT0gImZlbWFsZSIpDQpnZW5kZXIgPC0gY29Db3ZhcihnZW5kZXIpDQoNCm15ZGF0YSA8LSBzaWVuYURhdGFDcmVhdGUobmV0LCBnZW5kZXIpICNidWdneSAtIHdoeSBkb2VzbnQgdGhpcyB3b3JrPz8gDQpteWRhdGEgPC0gc2llbmFEYXRhQ3JlYXRlKG5ldCwgZGZfZWdvJGdlbmRlcikgI2J1Z2d5IC0gd2h5IGRvZXNudCB0aGlzIHdvcms/PyANCg0KDQpteWVmZiA8LSBnZXRFZmZlY3RzKG15ZGF0YSkgI2hhdmUgYSBsb29rIA0KbXllZmYNCg0KYGBgDQoNCg0KDQogDQoNCg0KIyMgU3RlcCAyLiBMb29rIGF0IGVmZmVjdHMNCmBgYHtyfQ0KZWZmZWN0c0RvY3VtZW50YXRpb24obXllZmYpDQoNCmBgYA0KDQoNCiMjIFN0ZXAgMzogTG9vayBhdCBpbnRpYWwgZGF0YQ0KDQotICAgIGdvb2QgZm9yIGRlY2lkaW5nIHN0YXRpc3RpY3MgdG8gdXNlLiANCg0KYGBge3J9DQpwcmludDAxUmVwb3J0KG15ZGF0YSkNCg0KIyBnaXZlcyBpbml0aWFsIGRlc2NyaXB0aW9uIG9mIGRhdGEgDQojIHJlYWRpbmcgbmV0d29yayB2YXJpYWJsZXMgLCBjb3ZhcmlhdGVzLCBkZW5zaXR5IG1lYXN1cmVzL2NoYW5nZXMgaW4gbmV0d29ya3MsIHRpZSBjaGFuZ2VzIGJldHdlZW4gc3Vic2VxdWVudCBvYnNlcnZhdGlvbnMuLi4gY2FsY3VsYXRlIGhvdyBtdWNoIG5ldHdvcmtzIGNoYW5nZWQgb3ZlciB0aW1lLiANCiMgZG9udCB1c2UgYmFsYW5jZSBjYWxjdWxhdGlvbiANCmBgYA0KDQoNCiMjIFN0ZXAgNDogQWRkIGVmZmVjdHMNCg0KRXhhbXBsZTogDQoNCmBgYHtyfQ0KDQoNCm5ldDFnIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeCh0c19uZXQxLCBtb2RlID0gImRpcmVjdGVkIikNCmNvb3JkcyA8LSBsYXlvdXRfKG5ldDFnLCBuaWNlbHkoKSkgICNsZXQgdXMga2VlcCB0aGUgbGF5b3V0DQpwYXIobWFyID0gYygwLjEsIDAuMSwgMC4xLCAwLjEpKQ0Kew0KICAgIHBsb3QuaWdyYXBoKG5ldDFnLCBsYXlvdXQgPSBjb29yZHMpDQogICAgZ3JhcGhpY3M6OmJveCgpDQp9DQoNCiMgZm9yIGV2ZXJ5IGFjdG9yLCB0aGVyZSBhcmUgMTAgb3B0aW9ucyAtIGVhY2ggYWN0b3IgY2FuIGJyZWFrIHRpZSwga2VlcCB0aWUvZG8gbm90aGluZywgb3IgYWRkIG5ldyB0aWUuIElmIHRpZSwgY2FuIGJyZWFrIG9yIGtlZXAuIElmIHRoZXJlIGlzIG5vIHRpZSwgY2FuIHJlbWFpbiAwIHRpZSBvciBmb3JtIGEgdGllLiANCg0KDQojIE5vdywgc2VsZWN0ICdyYW5kb20nIGFnZW50OiANCnNldC5zZWVkKDI0NTUzMjUzKQ0KZWdvIDwtIHRzX3NlbGVjdChuZXQgPSB0c19uZXQxKQ0KZWdvDQoNCg0KIyMjIyBOZXR3b3JrOiB0c19uZXQxLCBlZ28gPSBlZ280IChlZ28gNCBhbGxvd2VkIHRvIG1ha2UgbWluaXN0ZXBzKS4gcGFja2FnZSB0aGVuIHdpbGwgbGlzdCBhbGwgb2YgdGhlIGRpZmZlcmVudCBhZGphY2VuY3kgbWF0cmljZXMuIFNob3dzIGFsbCBvZiB0aGUgZGlmZmVyZW50IG5leHQgbWluaXN0ZXAgb3B0aW9ucyBmb3IgZWdvIDQuIA0KDQoNCiMjIyMgDQpvcHRpb25zIDwtIHRzX2FsdGVybmF0aXZlc19taW5pc3RlcChuZXQgPSB0c19uZXQxLCBlZ28gPSBlZ28pDQpvcHRpb25zDQoNCnBsb3RzIDwtIGxhcHBseShvcHRpb25zLCBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgsIG1vZGUgPSAiZGlyZWN0ZWQiKQ0KcGFyKG1hciA9IGMoMCwgMCwgMCwgMCkgKyAwLjEpDQpwYXIobWZyb3cgPSBjKDIsIDIpKQ0KDQpmcGxvdCA8LSBmdW5jdGlvbih4KSB7DQogICAgcGxvdC5pZ3JhcGgoeCwgbGF5b3V0ID0gY29vcmRzLCBtYXJnaW4gPSAwKQ0KICAgIGdyYXBoaWNzOjpib3goKQ0KfQ0KDQoNCnRzX2RlZ3JlZShuZXQgPSBvcHRpb25zW1sxXV0sIGVnbyA9IGVnbykNCnNhcHBseShvcHRpb25zLCB0c19kZWdyZWUsIGVnbyA9IGVnbykNCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQoNCklGIE5FRURFRCBMQVRFUjoNCg0KIyBOb3csIHRyeSB0byBsb29wIGluIGdlbmRlciANCiMjIE1ha2Ugc2ltcGxlIGFkaiBtYXRyaXggZm9yIGdlbmRlciANCmBgYHtyfQ0KDQoNCmBgYA0KDQoNCg0K